package com.connector.base.message.model;

import com.alibaba.fastjson.JSONObject;
import com.connector.base.config.InstantConfig;
import com.connector.base.connection.Connection;
import com.connector.base.connection.channel.NettyChannelSocketChannel;
import com.connector.base.connection.channel.SocketIoSocketChannel;
import com.connector.base.exception.ConnectorException;
import com.connector.base.exception.ServerException;
import com.connector.base.protocol.Command;
import com.connector.base.protocol.Packet;
import io.netty.channel.ChannelFutureListener;

import java.util.concurrent.atomic.AtomicInteger;

public abstract class BaseMessage implements Message
{
    private static final byte STATUS_DECODED = 1;
    private static final byte STATUS_ENCODED = 2;
    protected static final AtomicInteger ID_SEQ;
    protected transient Packet packet;
    protected transient Connection connection;
    private transient byte status;

    public BaseMessage() {
        this.status = 0;
    }

    public Packet getPacket() {
        return this.packet;
    }

    public BaseMessage(final Packet packet, final Connection connection) {
        this.status = 0;
        this.packet = packet;
        this.connection = connection;
    }

    @Override
    public void decodeBody() {
        if ((this.status & 0x1) == 0x0) {
            this.status |= 0x1;
            if (this.packet.getBodyLength() > 0) {
                this.decodeBody0();
            }
        }
    }

    @Override
    public void encodeBody() {
        if ((this.status & 0x2) == 0x0) {
            this.status |= 0x2;
            this.encodeBody0();
        }
    }

    private void encodeBody0() {
        final byte[] tmp = this.encode();
        if (InstantConfig.server.compress) {
            throw new ServerException("no support for body compression");
        }
        if (InstantConfig.server.encryption) {
            throw new ServerException("no support for body encryption");
        }
        this.packet.setBody(tmp);
    }

    private void decodeBody0() {
        final byte[] tmp = this.packet.getBody();
        if (InstantConfig.server.compress) {
            throw new ServerException("no support for body compression");
        }
        if (InstantConfig.server.encryption) {
            throw new ServerException("no support for body encryption");
        }
        if (tmp.length == 0) {
            throw new ServerException("message decode ex");
        }
        this.packet.setBody(tmp);
        this.decode(this.packet.getBody());
        this.packet.setBody(null);
    }

    public abstract byte[] encode();

    public abstract void decode(final byte[] body);

    @Override
    public Connection getConnection() {
        return this.connection;
    }

    @Override
    public void channelSend(final ChannelFutureListener listener) {
        this.encodeBody();
        if (this.connection.getSocketClient() instanceof NettyChannelSocketChannel) {
            this.connection.channelSend(this.packet, listener);
            return;
        }
        throw new ConnectorException("only Netty Channel support this method!");
    }

    @Override
    public void send(final String eventName) {
        this.encodeBody();
        if (this.connection.getSocketClient() instanceof SocketIoSocketChannel) {
            this.connection.sendEvent(eventName, JSONObject.toJSONString((Object)this));
            return;
        }
        throw new ConnectorException("only SocketIo Client support this method!");
    }

    public void close() {
        this.connection.disConnect();
    }

    public static OkMessage buildSuccessResponse(final Connection connection) throws Exception {
        final JSONObject dataObj = new JSONObject();
        dataObj.put("success", (Object)true);
        dataObj.put("msg", (Object)"发送成功");
        return new OkMessage(new Packet(Command.OK.cmd, (byte)1), connection).setType("0").setData(dataObj.toJSONString());
    }

    public static ErrorMessage buildErrorResponse(final Connection connection) {
        final JSONObject dataObj = new JSONObject();
        dataObj.put("success", (Object)false);
        dataObj.put("msg", (Object)"发送失败");
        return new ErrorMessage(new Packet(Command.ERROR.cmd, (byte)1), connection);
    }

    static {
        ID_SEQ = new AtomicInteger();
    }
}
